﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JRFinances.Models;
using JRFinances.ViewModels.VirtualTransactions;
using AutoMapper;
using JRFinances.ViewModels.Common;
using System.Data.Objects;

namespace JRFinances.Controllers
{
    [Authorize]
    public class VirtualTransactionsController : Controller
    {
        private JRFinancesEntities db = new JRFinancesEntities();

        public ViewResult ShowVirtualTransactionsHistory(string Company, string Buy, string Sell, string DateFrom, string DateTo)
        {
            var virtualTransactions = db.VirtualTransactions.Include("Company").Include("User").Where(n => n.User.Name == User.Identity.Name);

            if (!string.IsNullOrEmpty(Company))
            {
                virtualTransactions = virtualTransactions.Where(n => n.Company.Name == Company);
            }
            if (!string.IsNullOrEmpty(DateFrom))
            {
                DateTime dateTimeDate;
                if (DateTime.TryParse(DateFrom, out dateTimeDate))
                {
                    virtualTransactions = virtualTransactions.Where(n => EntityFunctions.TruncateTime(n.Date) >= dateTimeDate.Date); // dodanie filtrowania po dacie jesli wystapil taki parametr
                }
            }
            if (!string.IsNullOrEmpty(DateTo))
            {
                DateTime dateTimeDate;
                if (DateTime.TryParse(DateTo, out dateTimeDate))
                {
                    virtualTransactions = virtualTransactions.Where(n => EntityFunctions.TruncateTime(n.Date) <= dateTimeDate.Date); // dodanie filtrowania po dacie jesli wystapil taki parametr
                }
            }
            if (Buy == "on" && string.IsNullOrEmpty(Sell))
            {
                virtualTransactions = virtualTransactions.Where(n => n.Buy == true);
            }
            if (Sell == "on" && string.IsNullOrEmpty(Buy))
            {
                virtualTransactions = virtualTransactions.Where(n => n.Buy == false);
            }

            var virtualTransactionsViewModelList = new List<VirtualTransactionsHistoryViewModel>();
            virtualTransactions.ToList().ForEach(x => virtualTransactionsViewModelList.Add(Mapper.Map<VirtualTransactionsHistoryViewModel>(x)));
            return View(virtualTransactionsViewModelList);
        }

        public ActionResult Create()
        {
            string currentUser = User.Identity.Name;

            ViewBag.CompanyId = new SelectList(db.Companies, "CompanyId", "Name");
            var virtualTransaction = new CreateVirtualTransactionViewModel() { Date = DateTime.Now, Buy = true, CurrentSaldo = db.Users.Single(n => n.Name == currentUser).CurrentSaldo };
            return View(virtualTransaction);
        }

        [HttpPost]
        public ActionResult Create(CreateVirtualTransactionViewModel virtualTransactionViewModel)
        {
            if (ModelState.IsValid && virtualTransactionViewModel.IsTransactionAmountValid())
            {
                var virtualTransaction = Mapper.Map<VirtualTransaction>(virtualTransactionViewModel);
                virtualTransaction.UserId = db.Users.Single(n => n.Name == User.Identity.Name).UserId;
                db.VirtualTransactions.AddObject(virtualTransaction);

                var user = db.Users.Single(n => n.Name == User.Identity.Name);
                user.CurrentSaldo -= virtualTransactionViewModel.Price * virtualTransactionViewModel.Volume;

                db.SaveChanges();
                return RedirectToAction("ShowCurrentlyOwnedShares");
            }

            if (!virtualTransactionViewModel.IsTransactionAmountValid())
            {
                ModelState.AddModelError("", "Wartosc transakcji przekracza Twoje obecne saldo.");
            }

            ViewBag.CompanyId = new SelectList(db.Companies, "CompanyId", "Name", virtualTransactionViewModel.CompanyId);
            return View(virtualTransactionViewModel);
        }

        public ActionResult Delete(int id)
        {
            VirtualTransaction virtualTransaction = db.VirtualTransactions.Single(r => r.TransactionId == id);
            db.VirtualTransactions.DeleteObject(virtualTransaction);
            db.SaveChanges();
            return RedirectToAction("ShowCurrentlyOwnedShares");
        }

        public ActionResult Sell(string companyName)
        {
            var sharesBought = from n in db.VirtualTransactions
                               where n.User.Name == User.Identity.Name && n.Buy == true && n.Company.Name == companyName
                               group n by n.Company.Name into g
                               select new { Name = g.Key, VolumeBought = g.Sum(p => p.Volume) };

            var sharesSold = from n in db.VirtualTransactions
                             where n.User.Name == User.Identity.Name && n.Buy == false && n.Company.Name == companyName
                             group n by n.Company.Name into g
                             select new { Name = g.Key, VolumeSold = g.Sum(p => p.Volume) };

            var shares = from b in sharesBought
                         join s in sharesSold on b.Name equals s.Name into ps
                         from s in ps.DefaultIfEmpty()
                         select new { Name = b.Name, VolumeLeft = s.VolumeSold == null ? b.VolumeBought : b.VolumeBought - s.VolumeSold };

            var shareForSale = shares.Single();

            double currentPrice = db.Quotations.Where(n => n.Company.Name == shareForSale.Name).OrderByDescending(n => n.Date).First().Price;

            var sellVirtualTransactionViewModel = new SellVirtualTransactionViewModel() { CompanyName = shareForSale.Name, MaxVolume = shareForSale.VolumeLeft, Date = DateTime.Now, Price = currentPrice };

            return View(sellVirtualTransactionViewModel);
        }

        [HttpPost]
        public ActionResult Sell(SellVirtualTransactionViewModel sellVirtualTransactionViewModel)
        {
            if (ModelState.IsValid && sellVirtualTransactionViewModel.CustomValidation())
            {
                var VirtualTransaction = Mapper.Map<VirtualTransaction>(sellVirtualTransactionViewModel);
                VirtualTransaction.UserId = db.Users.Single(n => n.Name == User.Identity.Name).UserId;
                VirtualTransaction.CompanyId = db.Companies.Single(n => n.Name == sellVirtualTransactionViewModel.CompanyName).CompanyId;
                db.VirtualTransactions.AddObject(VirtualTransaction);
                db.SaveChanges();
                return RedirectToAction("ShowCurrentlyOwnedShares");
            }

            ModelState.AddModelError("", "Blad skladania zlecenia sprzedazy.");
            return View(sellVirtualTransactionViewModel);
        }

        public ActionResult ShowCurrentlyOwnedShares()
        {
            var currentlyOwnedSharesViewModel = GetCurrentlyOwnedShares();

            return View(currentlyOwnedSharesViewModel);
        }

        public ActionResult ShowStatistics(ShowStatisticsVirtualTransactionViewModel statsViewModel)
        {
            string userName = User.Identity.Name;

            var stats = new ShowStatisticsVirtualTransactionViewModel();

            var currentlyOwnedShares = GetCurrentlyOwnedShares();
            double valueOfCurrentlyOwnedShares = 0.0;

            foreach (CurrentlyOwnedSharesViewModel share in currentlyOwnedShares)
            {
                double currentPrice = db.Quotations.Where(n => n.Company.Name == share.Name).OrderByDescending(n => n.Date).First().Price;
                valueOfCurrentlyOwnedShares += currentPrice * share.VolumeLeft;
            }

            stats.BasicSaldo = db.Users.Single(n => n.Name == userName).BasicSaldo;
            stats.CurrentAccountWorth = db.Users.Single(n => n.Name == userName).CurrentSaldo + valueOfCurrentlyOwnedShares;

            var groupsWithUser = from gr in db.Groups
                                 join ug in db.UsersGroups on gr.GroupId equals ug.GroupId
                                 where ug.User.Name == userName
                                 select new { GroupId = gr.GroupId, GroupName = gr.Name };

            ViewBag.GroupId = new SelectList(groupsWithUser, "GroupId", "GroupName");

            stats.PlayersResults = new List<PlayerResultsViewModel>();

            if (statsViewModel.GroupId > 0)
            {
                var users = from u in db.Users
                            join ug in db.UsersGroups on u.UserId equals ug.UserId
                            where ug.GroupId == statsViewModel.GroupId && ug.Activated == true
                            select new { u.UserId, u.Name };

                foreach (var user in users)
                {
                    double currentWorthOfAccount = 0.0;
                    PlayerResultsViewModel playerResults = new PlayerResultsViewModel() { Name = user.Name };

                    currentWorthOfAccount = db.Users.Single(n => n.Name == user.Name).CurrentSaldo;

                    var sharesBought = from n in db.VirtualTransactions
                               where n.User.Name == user.Name && n.Buy == true
                               group n by n.Company.Name into g
                               select new { Name = g.Key, VolumeBought = g.Sum(p => p.Volume) };

                    var sharesSold = from n in db.VirtualTransactions
                             where n.User.Name == user.Name && n.Buy == false
                             group n by n.Company.Name into g
                             select new { Name = g.Key, VolumeSold = g.Sum(p => p.Volume) };

                    var shares = from b in sharesBought
                         join s in sharesSold on b.Name equals s.Name into ps
                         from s in ps.DefaultIfEmpty()
                         select new { Name = b.Name, VolumeLeft = s.VolumeSold == null ? b.VolumeBought : b.VolumeBought - s.VolumeSold };

                    shares = shares.Where(n => n.VolumeLeft > 0);

                    foreach (var share in shares)
                    {
                        double currentPrice = db.Quotations.Where(n => n.Company.Name == share.Name).OrderByDescending(n => n.Date).First().Price;
                        currentWorthOfAccount += currentPrice * share.VolumeLeft;
                    }

                    playerResults.CurrentWorthOfAccount = currentWorthOfAccount;

                    stats.PlayersResults.Add(playerResults);
                }
            }

            return View(stats);
        }

        public ActionResult ShowCurrentlyOwnedSharesChart()
        {
            var currentlyOwnedShares = GetCurrentlyOwnedShares();

            var xValues = new List<string>();
            var yValues = new List<double>();

            foreach (var item in currentlyOwnedShares)
            {
                xValues.Add(item.Name);
                yValues.Add(item.AvgPrice * item.VolumeLeft);
            }

            var chartViewModel = new ChartViewModel();

            chartViewModel.XValues = xValues.ToArray();
            chartViewModel.YValues = yValues.ToArray();

            return View(chartViewModel);
        }

        public double GetPriceForCompany(int id)
        {
            double currentPrice = db.Quotations.Where(n => n.CompanyId == id).OrderByDescending(n => n.Date).First().Price;

            return currentPrice;
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }

        private List<CurrentlyOwnedSharesViewModel> GetCurrentlyOwnedShares()
        {
            var currentlyOwnedSharesViewModel = new List<CurrentlyOwnedSharesViewModel>();

            var sharesBought = from n in db.VirtualTransactions
                               where n.User.Name == User.Identity.Name && n.Buy == true
                               group n by n.Company.Name into g
                               select new { Name = g.Key, VolumeBought = g.Sum(p => p.Volume), TotalPurchaseCost = g.Sum(p => p.Price) };

            var sharesSold = from n in db.VirtualTransactions
                             where n.User.Name == User.Identity.Name && n.Buy == false
                             group n by n.Company.Name into g
                             select new { Name = g.Key, VolumeSold = g.Sum(p => p.Volume) };

            var shares = from b in sharesBought
                         join s in sharesSold on b.Name equals s.Name into ps
                         from s in ps.DefaultIfEmpty()
                         select new { Name = b.Name, VolumeLeft = s.VolumeSold == null ? b.VolumeBought : b.VolumeBought - s.VolumeSold, AvgPrice = b.TotalPurchaseCost / b.VolumeBought };

            shares = shares.Where(n => n.VolumeLeft > 0);

            shares.ToList().ForEach(n => currentlyOwnedSharesViewModel.Add(new CurrentlyOwnedSharesViewModel() { Name = n.Name, VolumeLeft = n.VolumeLeft, AvgPrice = n.AvgPrice }));
            return currentlyOwnedSharesViewModel;
        }

    }
}
